/*
 * Copyright (c) 2011 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy
 * of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

package findreplace;

/**
 * Base class for building iteraters do find and replace on a string.
 *
 * AbstractSubstringReplacer provides a framework for building simple find and
 * replace matchers.
 *
 * Example:
 *  SimpleStringReplacer matcher = new SimpleStringReplacer("Hello world", "l");
 *  int loop = 0;
 *  while (matcher.next()) {
 *    loop += 1;
 *    match = matcher.currentMatch();
 *    if (loop % 2 != 0) {
 *      matcher.replaceWith("L");
 *    }
 *  }
 *  // matcher.result() => "HeLlo worLd"
 *
 * @author Tony Aiuto
 */

public abstract class AbstractSubstringReplacer {

  /** Text to scan */
  String text;
  /** Position in text */
  protected int currentPosition = 0;
  /** Length of current pattern match */
  protected int matchLength = 0;
  /** Output string */
  private StringBuffer out = new StringBuffer();

  public AbstractSubstringReplacer(String text) {
    this.text = text;
  }

  /** return the text after modification */
  public String result() {
    int remainder = text.length() - currentPosition;
    if (remainder > 0) skipOver(remainder);
    return out.toString();
  }

  /** return the current match */
  public String currentMatch() {
    return text.substring(currentPosition, currentPosition+matchLength);
  }

  /** Advance to the next token.
   *
   * Subclasses must implementation this method to update currentPosition to the
   * position of the next match and matchLength to the length of that match.
   *
   * @return true if there is another token found in the input stream.
   */
  public abstract boolean next();

  /**
   * Replace the current token with an alternate string.
   */
  public void replaceWith(String s) {
    out.append(s);
    currentPosition += matchLength;
    matchLength = 0;
  }

  /** skip n characters in the input stream and transfer to the result */
  protected void skipOver(int n) {
    out.append(text.substring(currentPosition, currentPosition+n));
    currentPosition += n;
  }

  /**
   * Resets the current matched element, passing it to the output if it was not
   * modified.
   */
  protected void clearMatch() {
    if (matchLength > 0) {
      skipOver(matchLength);
      matchLength = 0;
    }
  }
}
